﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO.Compression;
using System.Net;
using System.IO;
using System.Diagnostics;
using System.Threading.Tasks;
using System.ComponentModel;
using Ionic.Zip;
using Microsoft.Samples.AppUpdater;

namespace Booncraft
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            path = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData).ToString()) + "\\.booncraft\\";
            loadSettings();
        }

        public string path;

        class DownloadTask
        {
            public Uri link = null;
            public string save = null;
            public DownloadTask(Uri _link, string _save)
            {
                link = _link;
                save = _save;
            }
        }

        Queue<DownloadTask> downloads = new Queue<DownloadTask>();

        private void loadSettings()
        {
            try
            {
                string[] lines = File.ReadAllLines(path + "lastlogin");
                txtUsername.Text = lines[0];
                Password.Password = encryption.DecryptString(lines[1], "BoonCraft");
            }
            catch (Exception ex)
            {
                Console.Write(ex.Message);
            }
            try
            {
                string[] lines = File.ReadAllLines(path + "options.cfg");
                foreach (string x in lines)
                {
                    switch (x.Split(':')[0])
                    {
                        case "saveLogin": 
                            if (x.Split(':').Length == 2)
                            {
                                SaveLoginCHK.IsChecked = Convert.ToBoolean(x.Split(':')[1]);
                            }
                            break;
                        case "offlineMode" :
                            if (x.Split(':').Length == 2)
                            {
                                OfflineModeCHK.IsChecked = Convert.ToBoolean(x.Split(':')[1]);
                            }
                            break;
                    }
                }
            }
            catch (Exception ex)
            {
                Console.Write(ex.Message);
            }
        }
        private void Login_Click(object sender, RoutedEventArgs e)
        {
            double version = getVersion();

            Login.Content = "Logging In";

            if (!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
            if (!Directory.Exists(path + "bin\\"))
            {
                Directory.CreateDirectory(path + "bin\\");
            }
            if (!Directory.Exists(path + ".minecraft\\"))
            {
                Directory.CreateDirectory(path + ".minecraft\\");
            }
            double currentVer = getCurrentVersion();
            if (version > currentVer)
            {
                if (!Directory.Exists(path + "bin\\temp\\"))
                {
                    Directory.CreateDirectory(path + "bin\\temp\\");
                }
                WebClient webClient = new WebClient();
                webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(webClient_DownloadProgressChanged);
                webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(webClient_DownloadFileCompleted);
                webClient.DownloadFileAsync(new Uri("https://s3.amazonaws.com/MinecraftDownload/jinput.jar"), path + "bin\\jinput.jar");
                downloads.Enqueue(new DownloadTask(new Uri("https://s3.amazonaws.com/MinecraftDownload/lwjgl.jar"), path + "bin\\lwjgl.jar"));
                downloads.Enqueue(new DownloadTask(new Uri("https://s3.amazonaws.com/MinecraftDownload/lwjgl_util.jar"), path + "bin\\lwjgl_util.jar"));
                downloads.Enqueue(new DownloadTask(new Uri("https://s3.amazonaws.com/MinecraftDownload/minecraft.jar"), path + "bin\\minecraft.jar"));
                downloads.Enqueue(new DownloadTask(new Uri("https://s3.amazonaws.com/MinecraftDownload/windows_natives.jar"), path + "bin\\windows_natives.jar"));
                downloads.Enqueue(new DownloadTask(new Uri("http://352n.dyndns.org/ClientLauncherDownloads/ClassFiles.zip"), path + "ClassFiles.zip"));
                downloads.Enqueue(new DownloadTask(new Uri("http://352n.dyndns.org/ClientLauncherDownloads/launcherv1.jar"), path + "Launcherv1.jar"));
                downloads.Enqueue(new DownloadTask(new Uri("http://352n.dyndns.org/ClientLauncherDownloads/booncraftv" + version + ".zip"), path + "v" + version + ".zip"));
                Login.Content = "Download In Progress";
                Login.IsEnabled = false;
            }
            else
            {
                Login.Content = "Starting";
                startMinecraft();
            }
        }

        private void startMinecraft()
        {
            if (OfflineModeCHK.IsChecked == true)
            {
                startOffline();
            }
            else
            {
                startOnline();
            }
        }



        private void startOnline()
        {
            string appdatapath = @"" + path + @"";
            string sessionID = getSessionID();
            if (sessionID != null)
            {
                if (SaveLoginCHK.IsChecked == true)
                {
                    File.WriteAllLines(path + "lastlogin", new string[] { txtUsername.Text, encryption.EncryptString(Password.Password, "BoonCraft") });
                }
                string command = "java -jar " + path + "Launcherv1.jar " + txtUsername.Text + " " + sessionID + " " + getDownload();
                ProcessStartInfo procStartInfo = new ProcessStartInfo("cmd", "/c " + command);
                procStartInfo.UseShellExecute = false;
                procStartInfo.CreateNoWindow = false;
                procStartInfo.EnvironmentVariables.Remove("APPDATA");
                procStartInfo.EnvironmentVariables.Add("APPDATA", appdatapath);
                Process p = new Process();
                p.StartInfo = procStartInfo;
                p.Start();
                this.Close();
            }
            else
            {
                MessageBoxResult res = MessageBox.Show("        Invalid Login Details entered!\n Do you want to playing offline mode?", "Invalid Login", MessageBoxButton.YesNo);
                if (res == MessageBoxResult.Yes)
                {
                    startOffline();
                }
                else
                {
                    Login.Content = "Login";
                    Login.IsEnabled = true;
                }
            }
        }

        private void startOffline()
        {
            string appdatapath = @"" + path + @"";
            if (txtUsername.Text.Trim() != "")
            {
                string command = "java -jar " + path + "Launcherv1.jar " + txtUsername.Text + " 1" + " " + getDownload();
                ProcessStartInfo procStartInfo = new ProcessStartInfo("cmd", "/c " + command);
                procStartInfo.UseShellExecute = false;
                procStartInfo.CreateNoWindow = false;
                procStartInfo.EnvironmentVariables.Remove("APPDATA");
                procStartInfo.EnvironmentVariables.Add("APPDATA", appdatapath);
                Process p = new Process();
                p.StartInfo = procStartInfo;
                p.Start();
                this.Close();
            }
            else
            {
                string command = "java -jar " + path + "Launcherv1.jar Player" + " 1" + " " + getDownload();
                ProcessStartInfo procStartInfo = new ProcessStartInfo("cmd", "/c " + command);
                procStartInfo.UseShellExecute = false;
                procStartInfo.CreateNoWindow = false;
                procStartInfo.EnvironmentVariables.Remove("APPDATA");
                procStartInfo.EnvironmentVariables.Add("APPDATA", appdatapath);
                Process p = new Process();
                p.StartInfo = procStartInfo;
                p.Start();
                this.Close();
            }
        }


        void webClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            double bytesIn = double.Parse(e.BytesReceived.ToString());
            double totalBytes = double.Parse(e.TotalBytesToReceive.ToString());
            double percentage = bytesIn / totalBytes * 100;
            progressBar1.Value = int.Parse(Math.Truncate(percentage).ToString());
        }

        void webClient_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
        {
            if (downloads.Count > 0)
            {
                DownloadTask task = downloads.Dequeue();
                WebClient webClient = new WebClient();
                webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(webClient_DownloadProgressChanged);
                webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(webClient_DownloadFileCompleted);
                progressBar1.Value = 0;
                webClient.DownloadFileAsync(task.link, task.save);
            }
            else
            {
                Login.Content = "Extracting";
                unZip(path + "bin\\windows_natives.jar", path + "bin\\natives");
                unZip(path + "bin\\minecraft.jar", path + "bin\\temp\\");
                unZip(path + "v" + getVersion() + ".zip", path + ".minecraft\\");
                unZip(path + "ClassFiles.zip", path + "bin\\temp\\");
                Directory.Delete(path + @"bin\temp\META-INF", true);
                zipFolder(path + "bin\\temp", path + "bin\\minecraft.jar");
                Login.Content = "Cleaning";
                CleanUpDownloads();
                Login.Content = "Starting";
                startMinecraft();
            }
        }

        private void CleanUpDownloads()
        {
            Directory.Delete(path + "\\bin\\temp", true);
            File.Delete(path + "v" + getVersion().ToString() + ".zip");
            File.Delete(path + "ClassFiles.zip");
        }

        void zipFolder(string file, string location)
        {
            using (ZipFile zip = new ZipFile())
            {
                // add all those files to the ProjectX folder in the zip file
                zip.AddDirectory(file);
                zip.Comment = "This zip was created at " + System.DateTime.Now.ToString("G");
                zip.Save(location);
            }
        }

        void unZip(string file, string location)
        {
            using (ZipFile zip = ZipFile.Read(file))
            {
                foreach (ZipEntry files in zip)
                {
                    files.Extract(location, ExtractExistingFileAction.OverwriteSilently);
                }
            }
        }

        private string getDownload()
        {
            return "1";
        }

        private string getSessionID()
        {
            WebClient client = new WebClient();
            string retrieved = client.DownloadString("https://login.minecraft.net/?user=" + txtUsername.Text + "&password=" + Password.Password + "&version=12");
            string[] data = retrieved.Split(':');
            Console.WriteLine(retrieved);
            if (data.Length == 4)
                return data[3];
            else
                return null;
        }

        private double getVersion()
        {
            WebClient client = new WebClient();
            string retrieved = client.DownloadString("http://352n.dyndns.org/ClientLauncherDownloads/version.html");
            retrieved = retrieved.Substring(0, 4);
            if (retrieved != null || retrieved.Trim() != "")
                return Convert.ToDouble(retrieved);
            else
                return 0.0;
        }

        private double getCurrentVersion()
        {
            WebClient client = new WebClient();
            string retrieved = null;
            if (File.Exists(path + ".minecraft/version"))
            {
                retrieved = File.ReadAllText(path + ".minecraft/version");
            }
            if (retrieved != null)
                return Convert.ToDouble(retrieved);
            else
                return 0.0;
        }

        private void Window_Closing_1(object sender, CancelEventArgs e)
        {
            Application.Current.Shutdown(0);
        }

        private void SaveOptions_Click(object sender, RoutedEventArgs e)
        {
            string[] lines = new string[2]{"saveLogin:" + SaveLoginCHK.IsChecked,"offlineMode:" + OfflineModeCHK.IsChecked};
            File.WriteAllLines(path + "options.cfg", lines);
        }
    }

    class encryption
    {
        public static string EncryptString(string Message, string Passphrase)
        {
            byte[] Results;
            System.Text.UTF8Encoding UTF8 = new System.Text.UTF8Encoding();

            // Step 1. We hash the passphrase using MD5
            // We use the MD5 hash generator as the result is a 128 bit byte array
            // which is a valid length for the TripleDES encoder we use below

            MD5CryptoServiceProvider HashProvider = new MD5CryptoServiceProvider();
            byte[] TDESKey = HashProvider.ComputeHash(UTF8.GetBytes(Passphrase));

            // Step 2. Create a new TripleDESCryptoServiceProvider object
            TripleDESCryptoServiceProvider TDESAlgorithm = new TripleDESCryptoServiceProvider();

            // Step 3. Setup the encoder
            TDESAlgorithm.Key = TDESKey;
            TDESAlgorithm.Mode = CipherMode.ECB;
            TDESAlgorithm.Padding = PaddingMode.PKCS7;

            // Step 4. Convert the input string to a byte[]
            byte[] DataToEncrypt = UTF8.GetBytes(Message);

            // Step 5. Attempt to encrypt the string
            try
            {
                ICryptoTransform Encryptor = TDESAlgorithm.CreateEncryptor();
                Results = Encryptor.TransformFinalBlock(DataToEncrypt, 0, DataToEncrypt.Length);
            }
            finally
            {
                // Clear the TripleDes and Hashprovider services of any sensitive information
                TDESAlgorithm.Clear();
                HashProvider.Clear();
            }

            // Step 6. Return the encrypted string as a base64 encoded string
            return Convert.ToBase64String(Results);
        }

        public static string DecryptString(string Message, string Passphrase)
        {
            byte[] Results;
            System.Text.UTF8Encoding UTF8 = new System.Text.UTF8Encoding();

            // Step 1. We hash the passphrase using MD5
            // We use the MD5 hash generator as the result is a 128 bit byte array
            // which is a valid length for the TripleDES encoder we use below

            MD5CryptoServiceProvider HashProvider = new MD5CryptoServiceProvider();
            byte[] TDESKey = HashProvider.ComputeHash(UTF8.GetBytes(Passphrase));

            // Step 2. Create a new TripleDESCryptoServiceProvider object
            TripleDESCryptoServiceProvider TDESAlgorithm = new TripleDESCryptoServiceProvider();

            // Step 3. Setup the decoder
            TDESAlgorithm.Key = TDESKey;
            TDESAlgorithm.Mode = CipherMode.ECB;
            TDESAlgorithm.Padding = PaddingMode.PKCS7;

            // Step 4. Convert the input string to a byte[]
            byte[] DataToDecrypt = Convert.FromBase64String(Message);

            // Step 5. Attempt to decrypt the string
            try
            {
                ICryptoTransform Decryptor = TDESAlgorithm.CreateDecryptor();
                Results = Decryptor.TransformFinalBlock(DataToDecrypt, 0, DataToDecrypt.Length);
            }
            finally
            {
                // Clear the TripleDes and Hashprovider services of any sensitive information
                TDESAlgorithm.Clear();
                HashProvider.Clear();
            }

            // Step 6. Return the decrypted string in UTF8 format
            return UTF8.GetString(Results);
        }
    }
}
